#include <crt_sock.h>

_sock_t _createsock(
	int af,
	int type,
	int protocol) 
{
	_sock_t s;
	s = socket(af, type, protocol);
	return s;
}

int _closesock(_sock_t s)
{
	if (s != INVALID_SOCKET)
	{
#if (TARGET_OS == OS_WINDOWS)
		return closesocket(s);
#elif (TARGET_OS == OS_POSIX)
		return close(s);
#endif
	}
	return S_ERROR;
}
int _shutdown_sock(_sock_t s, int howrw)
{
	int rc = 0;
	rc_assert(s != INVALID_SOCKET, S_ERROR)

	rc = shutdown(s, howrw);

	return rc;
}
int SetError(_sock_t* s, int turn)
{
	rc_assert(*s != INVALID_SOCKET, S_ERROR)
	int error = turn;
	setsockopt(*s, SOL_SOCKET, SO_ERROR, (void*)&error, sizeof(int));
	return S_SUCCESS;
}
int SetReuseAddr(_sock_t* s, int turn)
{
	rc_assert(*s != INVALID_SOCKET,S_ERROR)
	int reuse = turn;
	setsockopt(*s, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse, sizeof(reuse));
	return S_SUCCESS;
}
int SetNoDelay(_sock_t* s, int turn)
{
	rc_assert(*s != INVALID_SOCKET, S_ERROR)
	return S_SUCCESS;
}
int SetBroadCast(_sock_t* s, int turn)
{
	rc_assert(*s != INVALID_SOCKET, S_ERROR)
	int bBroadcast = turn;
	setsockopt(*s, SOL_SOCKET, SO_BROADCAST, (const char*)&bBroadcast, sizeof(int));
	return S_SUCCESS;
}
int SetDontRoute(_sock_t* s, int turn)
{
	rc_assert(*s != INVALID_SOCKET, S_ERROR)
	int dontroute = turn;
	setsockopt(*s, SOL_SOCKET, SO_DONTROUTE, (const char*)&dontroute, sizeof(dontroute));
	return S_SUCCESS;
}
int SetDoLinger(_sock_t* s, int turn)
{
#if (TARGET_OS == OS_WINDOWS)
	rc_assert(*s != INVALID_SOCKET, S_ERROR)
	int bDontlinger = turn;
	setsockopt(*s, SOL_SOCKET, SO_DONTLINGER, (const char*)&bDontlinger, sizeof(int));
#endif

	return S_SUCCESS;
}
int SetLinger(_sock_t* s, int sec)
{
	rc_assert(*s != INVALID_SOCKET, S_ERROR)
	struct linger so_linger;
	so_linger.l_onoff = 1;
	so_linger.l_linger = sec;
	setsockopt(*s, SOL_SOCKET, SO_LINGER, (const char*)&so_linger, sizeof(so_linger));
	return S_SUCCESS;
}
int SetKeepalive(_sock_t* s, int turn)
{
	rc_assert(*s != INVALID_SOCKET, S_ERROR)
	int	bKeepalive = turn;
	setsockopt(*s, SOL_SOCKET, SO_KEEPALIVE, (const char*)&bKeepalive, sizeof(int));
	return S_SUCCESS;
}
int SetCork(_sock_t* s, int turn)
{
	rc_assert(*s != INVALID_SOCKET, S_ERROR)
	int set = 0;
	set = turn;
#if (TARGET_OS == OS_POSIX)
	setsockopt(*s, SOL_TCP, TCP_CORK, (void *)&set, sizeof(int));
#endif
	return S_SUCCESS;
}
int SetNoSigPipe(_sock_t* s, int turn)
{
	rc_assert(*s != INVALID_SOCKET, S_ERROR)

	int set = 0;
	set = turn;
	//unix no found MSG_NOSIGNAL, but have SO_NOSIGPIPE
#if (TARGET_OS != OS_WINDOWS)

#if defined(SO_NOSIGPIPE) && !defined(MSG_NOSIGNAL)
#define MSG_NOSIGNAL SO_NOSIGPIPE
#endif
	setsockopt(*s, SOL_SOCKET, MSG_NOSIGNAL, (void *)&set, sizeof(int));
#endif

	return S_SUCCESS;
}
int SetNonblock(_sock_t* s, int turn)
{
	rc_assert(*s != INVALID_SOCKET, S_ERROR)
	return S_SUCCESS;
}
int SetSendTimeOut(_sock_t* s, int sec)
{
	rc_assert(*s != INVALID_SOCKET, S_ERROR)
	struct timeval timeout;
	timeout.tv_sec = sec;
	timeout.tv_usec = 0;
	socklen_t len = sizeof(timeout);
	setsockopt(*s, SOL_SOCKET, SO_SNDTIMEO, (const char*)&timeout, len);
	return S_SUCCESS;
}
int SetRecvTimeOut(_sock_t* s, int sec)
{
	rc_assert(*s != INVALID_SOCKET, S_ERROR)
	struct timeval timeout;
	timeout.tv_sec = sec;
	timeout.tv_usec = 0;
	socklen_t len = sizeof(timeout);
	setsockopt(*s, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, len);
	return S_SUCCESS;
}
int SetConTimeOut(_sock_t* s, int sec)
{
	rc_assert(*s != INVALID_SOCKET, S_ERROR)
	return S_SUCCESS;
}
int SetSendBufLen(_sock_t* s, int size)
{
	rc_assert(*s != INVALID_SOCKET, S_ERROR)
	long nRecvBuf = size * 1024;
	setsockopt(*s, SOL_SOCKET, SO_RCVBUF, (const char*)&nRecvBuf, sizeof(long));
	return S_SUCCESS;
}
int SetRecvBufLen(_sock_t* s, int size)
{
	rc_assert(*s != INVALID_SOCKET, S_ERROR)
	long nRecvBuf = size * 1024;
	setsockopt(*s, SOL_SOCKET, SO_RCVBUF, (const char*)&nRecvBuf, sizeof(long));
	return S_SUCCESS;
}
int SetSendLoWat(_sock_t* s, int size)
{
	rc_assert(*s != INVALID_SOCKET, S_ERROR)
	int nSendLowAT = size;
	setsockopt(*s, SOL_SOCKET, SO_SNDLOWAT, (void*)&nSendLowAT, sizeof(nSendLowAT));
	return S_SUCCESS;
}
int SetRecvLoWat(_sock_t* s, int size)
{
	rc_assert(*s != INVALID_SOCKET, S_ERROR)
	int nRecvLowAT = size;
	setsockopt(*s, SOL_SOCKET, SO_RCVLOWAT, (void*)&nRecvLowAT, sizeof(nRecvLowAT));
	return S_SUCCESS;
}



#if (TARGET_OS == OS_WINDOWS)

int socketpair(int d, int type, int protocol, _sock_t sv[2])
{
	typedef int socklen_t;
	union {
		struct sockaddr_in inaddr;
		struct sockaddr addr;
	} a;

	_sock_t listener;
	int e;

	socklen_t addrlen = sizeof(a.inaddr);
	DWORD flags = 0;
	int reuse = 1;

	if (sv == 0) {
		WSASetLastError(WSAEINVAL);
		return SOCKET_ERROR;
	}

	listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (listener == INVALID_SOCKET)
	return SOCKET_ERROR;

	memset(&a, 0, sizeof(a));
	a.inaddr.sin_family = AF_INET;
	a.inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
	a.inaddr.sin_port = 0;

	sv[0] = sv[1] = INVALID_SOCKET;
	do {
		setsockopt(listener, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (char*)&reuse, (socklen_t)sizeof(reuse));
		if (bind(listener, &a.addr, sizeof(a.inaddr)) == SOCKET_ERROR)
			break;
		if (getsockname(listener, &a.addr, &addrlen) == SOCKET_ERROR)
			break;
		if (listen(listener, 1) == SOCKET_ERROR)
			break;
		sv[0] = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, flags);
		if (sv[0] == INVALID_SOCKET)
			break;
		if (connect(sv[0], &a.addr, sizeof(a.inaddr)) == SOCKET_ERROR)
			break;
		sv[1] = accept(listener, NULL, NULL);
		if (sv[1] == INVALID_SOCKET)
			break;

		closesocket(listener);
		return 0;

	} while (0);

	e = WSAGetLastError();
	closesocket(listener);
	closesocket(sv[0]);
	closesocket(sv[1]);
	WSASetLastError(e);
	return SOCKET_ERROR;
}

#endif


